use crate::error::Result;
use crate::storage::data_types::traits::{DataType, SetOperations};
use std::any::Any;
use std::collections::HashSet;
use rand::seq::SliceRandom;

/// Set data type implementation
/// 
/// Represents a Redis set value, which is an unordered collection of unique strings.
/// Implemented using HashSet for efficient membership testing and operations.
#[derive(Debug, Clone)]
pub struct SetType {
    data: HashSet<String>,
}

impl SetType {
    /// Create a new empty set
    pub fn new() -> Self {
        Self {
            data: HashSet::new(),
        }
    }
    
    /// Create a set from an existing HashSet
    pub fn from_set(data: HashSet<String>) -> Self {
        Self { data }
    }
    
    /// Create a set from a Vec (removes duplicates)
    pub fn from_vec(data: Vec<String>) -> Self {
        Self {
            data: data.into_iter().collect(),
        }
    }
    
    /// Get the underlying HashSet reference
    pub fn as_set(&self) -> &HashSet<String> {
        &self.data
    }
    
    /// Get the underlying HashSet mutable reference
    pub fn as_set_mut(&mut self) -> &mut HashSet<String> {
        &mut self.data
    }
    
    /// Clear all elements
    pub fn clear(&mut self) {
        self.data.clear();
    }
    
    /// Convert to Vec (order is not guaranteed)
    pub fn to_vec(&self) -> Vec<String> {
        self.data.iter().cloned().collect()
    }
    
    /// Calculate memory usage
    fn calculate_memory_usage(&self) -> usize {
        let base_size = std::mem::size_of::<Self>();
        let set_overhead = self.data.capacity() * std::mem::size_of::<String>();
        let content_size: usize = self.data
            .iter()
            .map(|s| s.len())
            .sum();
        
        base_size + set_overhead + content_size
    }
}

impl Default for SetType {
    fn default() -> Self {
        Self::new()
    }
}

impl DataType for SetType {
    fn type_name(&self) -> &'static str {
        "set"
    }
    
    fn debug_string(&self) -> String {
        format!("SetType({} members)", self.data.len())
    }
    
    fn clone_data(&self) -> Box<dyn DataType> {
        Box::new(self.clone())
    }
    
    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }
    
    fn memory_usage(&self) -> usize {
        self.calculate_memory_usage()
    }
    
    fn as_any(&self) -> &dyn Any {
        self
    }
    
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

impl SetOperations for SetType {
    fn sadd(&mut self, members: Vec<String>) -> Result<usize> {
        let mut added_count = 0;
        for member in members {
            if self.data.insert(member) {
                added_count += 1;
            }
        }
        Ok(added_count)
    }
    
    fn srem(&mut self, members: &[String]) -> Result<usize> {
        let mut removed_count = 0;
        for member in members {
            if self.data.remove(member) {
                removed_count += 1;
            }
        }
        Ok(removed_count)
    }
    
    fn sismember(&self, member: &str) -> Result<bool> {
        Ok(self.data.contains(member))
    }
    
    fn smembers(&self) -> Result<HashSet<String>> {
        Ok(self.data.clone())
    }
    
    fn scard(&self) -> Result<usize> {
        Ok(self.data.len())
    }
    
    fn srandmember(&self, count: Option<i64>) -> Result<Vec<String>> {
        let members: Vec<String> = self.data.iter().cloned().collect();
        
        match count {
            None => {
                // Return a single random member
                if members.is_empty() {
                    Ok(Vec::new())
                } else {
                    let mut rng = rand::thread_rng();
                    let member = members.choose(&mut rng).unwrap().clone();
                    Ok(vec![member])
                }
            }
            Some(0) => Ok(Vec::new()),
            Some(n) if n > 0 => {
                // Return up to n distinct random members
                let count = std::cmp::min(n as usize, members.len());
                let mut rng = rand::thread_rng();
                let mut selected = members;
                selected.shuffle(&mut rng);
                selected.truncate(count);
                Ok(selected)
            }
            Some(n) => {
                // Return n random members (with possible duplicates)
                let count = (-n) as usize;
                let mut result = Vec::with_capacity(count);
                let mut rng = rand::thread_rng();
                
                for _ in 0..count {
                    if let Some(member) = members.choose(&mut rng) {
                        result.push(member.clone());
                    }
                }
                Ok(result)
            }
        }
    }
    
    fn spop(&mut self, count: Option<usize>) -> Result<Vec<String>> {
        let count = count.unwrap_or(1);
        let mut result = Vec::new();
        
        if self.data.is_empty() {
            return Ok(result);
        }
        
        let members: Vec<String> = self.data.iter().cloned().collect();
        let mut rng = rand::thread_rng();
        
        let actual_count = std::cmp::min(count, members.len());
        let mut selected = members;
        selected.shuffle(&mut rng);
        
        for _ in 0..actual_count {
            if let Some(member) = selected.pop() {
                self.data.remove(&member);
                result.push(member);
            }
        }
        
        Ok(result)
    }
    
    fn sunion(&self, other_sets: &[&dyn SetOperations]) -> Result<HashSet<String>> {
        let mut result = self.data.clone();
        
        for other_set in other_sets {
            let other_members = other_set.smembers()?;
            result.extend(other_members);
        }
        
        Ok(result)
    }
    
    fn sinter(&self, other_sets: &[&dyn SetOperations]) -> Result<HashSet<String>> {
        if other_sets.is_empty() {
            return Ok(self.data.clone());
        }
        
        let mut result = self.data.clone();
        
        for other_set in other_sets {
            let other_members = other_set.smembers()?;
            result = result.intersection(&other_members).cloned().collect();
            
            // Early exit if intersection becomes empty
            if result.is_empty() {
                break;
            }
        }
        
        Ok(result)
    }
    
    fn sdiff(&self, other_sets: &[&dyn SetOperations]) -> Result<HashSet<String>> {
        let mut result = self.data.clone();
        
        for other_set in other_sets {
            let other_members = other_set.smembers()?;
            result = result.difference(&other_members).cloned().collect();
            
            // Early exit if difference becomes empty
            if result.is_empty() {
                break;
            }
        }
        
        Ok(result)
    }
}

impl From<Vec<String>> for SetType {
    fn from(data: Vec<String>) -> Self {
        Self::from_vec(data)
    }
}

impl From<HashSet<String>> for SetType {
    fn from(data: HashSet<String>) -> Self {
        Self::from_set(data)
    }
}

impl From<&[String]> for SetType {
    fn from(data: &[String]) -> Self {
        Self::from_vec(data.to_vec())
    }
}

impl FromIterator<String> for SetType {
    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
        Self {
            data: iter.into_iter().collect(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_set_basic_operations() {
        let mut set = SetType::new();
        
        assert!(set.is_empty());
        assert_eq!(set.scard().unwrap(), 0);
        
        // Test sadd
        let added = set.sadd(vec!["a".to_string(), "b".to_string(), "c".to_string()]).unwrap();
        assert_eq!(added, 3);
        assert_eq!(set.scard().unwrap(), 3);
        
        // Test adding duplicate
        let added = set.sadd(vec!["a".to_string(), "d".to_string()]).unwrap();
        assert_eq!(added, 1); // Only "d" was added
        assert_eq!(set.scard().unwrap(), 4);
    }
    
    #[test]
    fn test_set_membership() {
        let mut set = SetType::new();
        set.sadd(vec!["a".to_string(), "b".to_string(), "c".to_string()]).unwrap();
        
        // Test sismember
        assert!(set.sismember("a").unwrap());
        assert!(set.sismember("b").unwrap());
        assert!(set.sismember("c").unwrap());
        assert!(!set.sismember("d").unwrap());
        
        // Test smembers
        let members = set.smembers().unwrap();
        assert_eq!(members.len(), 3);
        assert!(members.contains("a"));
        assert!(members.contains("b"));
        assert!(members.contains("c"));
    }
    
    #[test]
    fn test_set_remove() {
        let mut set = SetType::new();
        set.sadd(vec!["a".to_string(), "b".to_string(), "c".to_string()]).unwrap();
        
        // Test srem
        let removed = set.srem(&["a".to_string(), "d".to_string()]).unwrap();
        assert_eq!(removed, 1); // Only "a" was removed
        assert_eq!(set.scard().unwrap(), 2);
        assert!(!set.sismember("a").unwrap());
        assert!(set.sismember("b").unwrap());
        assert!(set.sismember("c").unwrap());
    }
    
    #[test]
    fn test_set_random_operations() {
        let mut set = SetType::new();
        set.sadd(vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string(), "e".to_string()]).unwrap();
        
        // Test srandmember with no count
        let random = set.srandmember(None).unwrap();
        assert_eq!(random.len(), 1);
        assert!(set.sismember(&random[0]).unwrap());
        
        // Test srandmember with positive count
        let random = set.srandmember(Some(3)).unwrap();
        assert_eq!(random.len(), 3);
        for member in &random {
            assert!(set.sismember(member).unwrap());
        }
        
        // Test srandmember with count larger than set size
        let random = set.srandmember(Some(10)).unwrap();
        assert_eq!(random.len(), 5); // Set has only 5 members
        
        // Test spop
        let original_size = set.scard().unwrap();
        let popped = set.spop(Some(2)).unwrap();
        assert_eq!(popped.len(), 2);
        assert_eq!(set.scard().unwrap(), original_size - 2);
        
        for member in &popped {
            assert!(!set.sismember(member).unwrap());
        }
    }
    
    #[test]
    fn test_set_operations() {
        let mut set1 = SetType::new();
        set1.sadd(vec!["a".to_string(), "b".to_string(), "c".to_string()]).unwrap();
        
        let mut set2 = SetType::new();
        set2.sadd(vec!["b".to_string(), "c".to_string(), "d".to_string()]).unwrap();
        
        let mut set3 = SetType::new();
        set3.sadd(vec!["c".to_string(), "d".to_string(), "e".to_string()]).unwrap();
        
        // Test sunion
        let union = set1.sunion(&[&set2, &set3]).unwrap();
        assert_eq!(union.len(), 5); // {a, b, c, d, e}
        assert!(union.contains("a"));
        assert!(union.contains("b"));
        assert!(union.contains("c"));
        assert!(union.contains("d"));
        assert!(union.contains("e"));
        
        // Test sinter
        let intersection = set1.sinter(&[&set2]).unwrap();
        assert_eq!(intersection.len(), 2); // {b, c}
        assert!(intersection.contains("b"));
        assert!(intersection.contains("c"));
        
        let intersection_all = set1.sinter(&[&set2, &set3]).unwrap();
        assert_eq!(intersection_all.len(), 1); // {c}
        assert!(intersection_all.contains("c"));
        
        // Test sdiff
        let difference = set1.sdiff(&[&set2]).unwrap();
        assert_eq!(difference.len(), 1); // {a}
        assert!(difference.contains("a"));
        
        let difference_all = set1.sdiff(&[&set2, &set3]).unwrap();
        assert_eq!(difference_all.len(), 1); // {a}
        assert!(difference_all.contains("a"));
    }
    
    #[test]
    fn test_set_conversions() {
        let vec_data = vec!["a".to_string(), "b".to_string(), "c".to_string(), "a".to_string()];
        let set = SetType::from(vec_data);
        
        assert_eq!(set.scard().unwrap(), 3); // Duplicates removed
        assert!(set.sismember("a").unwrap());
        assert!(set.sismember("b").unwrap());
        assert!(set.sismember("c").unwrap());
        
        let hash_set: HashSet<String> = ["x".to_string(), "y".to_string()].into_iter().collect();
        let set = SetType::from(hash_set);
        assert_eq!(set.scard().unwrap(), 2);
    }
    
    #[test]
    fn test_set_empty_operations() {
        let mut empty_set = SetType::new();
        
        // Operations on empty set
        assert_eq!(empty_set.srandmember(None).unwrap().len(), 0);
        assert_eq!(empty_set.srandmember(Some(5)).unwrap().len(), 0);
        assert_eq!(empty_set.spop(Some(3)).unwrap().len(), 0);
        
        let members = empty_set.smembers().unwrap();
        assert!(members.is_empty());
        
        // Union with empty set
        let mut other_set = SetType::new();
        other_set.sadd(vec!["a".to_string()]).unwrap();
        
        let union = empty_set.sunion(&[&other_set]).unwrap();
        assert_eq!(union.len(), 1);
        assert!(union.contains("a"));
        
        // Intersection with empty set
        let intersection = empty_set.sinter(&[&other_set]).unwrap();
        assert!(intersection.is_empty());
    }
    
    #[test]
    fn test_data_type_trait() {
        let set = SetType::new();
        
        assert_eq!(set.type_name(), "set");
        assert!(set.is_empty());
        assert!(set.memory_usage() > 0);
        
        let cloned = set.clone_data();
        assert_eq!(cloned.type_name(), "set");
    }
}